library(tidyverse)
library(readxl)
library(lubridate)
library(viridis)

setwd("~/Box/Shareable Files/Stanford/Classes/SPARK/Screen Analysis")

Import datasets

plate1_red_raw <- read_tsv("data/plate 1 total integrated intensity.txt", skip=6)
plate2_red_raw <- read_tsv("data/plate 2 total integrated intensity.txt", skip=6)

plate1_green_raw <- read_tsv("data/live object area um2 ver 1.txt", skip=6)
plate2_green_raw <- read_tsv("data/live object area um2 ver 2.txt", skip=6)

annotations <- read_xlsx("data/annotations.xlsx")

Define a new theme for graphs

theme_my <- function(base_size = 10, base_family = "Helvetica")
{
  txt <- element_text(size = 10, colour = "black", face = "plain")
  bold_txt <- element_text(size = 10, colour = "black", face = "bold")
  
  theme_bw(base_size = base_size, base_family = base_family) +
    theme(
      
      legend.key = element_blank(), 
      strip.background = element_blank(), 
      
      text = txt, 
      plot.title = txt, 
      
      axis.title = element_text(size = 8), 
      axis.text = element_text(size = 6), 
      
      legend.title = element_text(size = 10, face="bold"), 
      legend.text = element_text(size = 8),
      
      axis.ticks.length=unit(4, "pt"),
      
      #axis.text.x = element_text(margin=unit(c(4,4,4,4), "pt")),
      #axis.text.x.top =  element_blank(),
      #axis.text.y = element_text(margin=unit(c(4,4,4,4), "pt")),
      #axis.text.y.right = element_blank(),
      panel.grid=element_blank(),
      plot.margin = unit(c(base_size, base_size, base_size, base_size), "pt")
    ) 
}

Match annotations to each column

annotations_parsed <- annotations %>%
  pivot_longer(everything(), names_to = "cell", values_to="treatment") %>%
  separate(treatment, into=c("treatment", "dose"), sep="_")

Create a function to merge dataset and annotate

merge <- function(plate1_raw, plate2_raw, notes){
  
  plate1 <- plate1_raw %>%
    select(-`Date Time`) %>%
    pivot_longer(-Elapsed, names_to="cell", values_to="signal") %>%
    mutate(id=paste0(cell,"_1"))
  
  plate2 <- plate2_raw %>%
    select(-`Date Time`) %>%
    pivot_longer(-Elapsed, names_to="cell", values_to="signal") %>%
    mutate(id=paste0(cell,"_2"))

  df_new <- plate1 %>%
    full_join(plate2) %>%
    left_join(notes, by="cell") %>%
    mutate(dose=as.numeric(dose))
  
  return(df_new)
}

Parse the data for plates 1 and 2 and merge annotations in. Perform this for green plates (viability) and red (phagocytosis). Then create a single master dataset with phagocytosis and viability.

df_live <- merge(plate1_green_raw, plate2_green_raw, annotations_parsed)
df_red <- merge(plate1_red_raw, plate2_red_raw, annotations_parsed)

Graph the viability data

df_live_graph <- df_live %>%
  group_by(dose, treatment) %>%
  mutate(signal_average=mean(signal),
            range=max(signal)-min(signal),
            sd=sd(signal)) %>%
  ungroup() %>%
  mutate(maxLive=first(signal_average),
         sdLive=sd/signal_average*maxLive) %>%
  mutate(percLive=signal_average/maxLive*100)

df_live_graph %>%
  filter(!str_detect(treatment, "DMSO")&!str_detect(treatment, "nothing")) %>%
  distinct(treatment, dose, percLive) %>%
  ggplot(aes(dose, percLive, color=dose)) +
  geom_smooth(method = "loess", col="black") + 
  geom_point() +
  #geom_errorbar(aes(ymax=signal_average+range/2, ymin=signal_average-range/2), width=0) +
  #geom_errorbar(aes(ymax=percLive+sdLive, ymin=percLive-sdLive), width=0) +
  #geom_smooth(method = lm, formula = y ~ splines::bs(x, 1), color="red") +
  #geom_smooth(method = lm, formula = y ~ log1p(x), color="red", se=F) +
  scale_color_viridis(direction=-1, option="magma", begin=0, end=.8) +
  geom_point(data=df_live_graph%>%filter(percLive<70), color="red", size=3, shape=21) +
  scale_x_log10() +
  #labs(x="Dose (nM)", y="Percent Vaibility") +
  labs(x="Dose (nM)", y="Calcein AM (%)") +
  facet_grid(.~treatment) +
  geom_hline(yintercept = 70, linetype = "dashed", color="red") +
  theme_my()


ggsave("viability-70perc-threshold-new.pdf", height=1.75, width=12)

Phagocytosis data. Start by adding in the viability data

df <- df_red %>%
  full_join(df_live_graph, by="id") %>%
  select(-c("Elapsed.y", "cell.y", "treatment.y", "dose.y")) %>%
  rename(time=Elapsed.x, cell=cell.x, signal=signal.x, treatment=treatment.x, dose=dose.x, signal.green=signal.y,
         range.green=range, range.sd=sd)

Graph all phagocytosis data.

Try normalizing the phagocytosis signal to percent viability.

Graph the normalized phagocytosis data again. Also gate only on conditions where: - viability is above 70% - sd is not huge (sd must be half the mean of a given value) - most of the data points are still present for a given condition

df_norm_subset <- df_norm %>%
  filter(percLive>70) %>% # Gate only on wells where viability determined to be greater than 70&
  group_by(treatment, dose, time) %>%
  mutate(signal_average=mean(signal),
         range=max(signal)-min(signal),
         sd=sd(signal)) %>%
  filter(sd<signal_average/2) %>%
  ungroup() %>%
  group_by(treatment, dose) %>%
  filter(n()>48) #Here gating on treatments / doses where most of the data poitns are still present

df_norm_subset %>%
  ggplot(aes(time, signal_average, group=dose, color=dose)) +
    geom_smooth(method = lm, formula = y ~ log1p(x), color="black", se=F) +
    geom_point() +
    #geom_errorbar(aes(ymax=signal_average+range/2, ymin=signal_average-range/2), width=0) +
    geom_errorbar(aes(ymax=signal_average+sd, ymin=signal_average-sd), width=0) +
    scale_color_viridis(direction=-1, option="magma", begin=0, end=.8) +
    facet_grid(treatment~dose)+
    theme_my()

Graph Salmeterol phagocytosis data only.

Graph Moxonidine phagocytosis data only.

Perform area under the curve analysis. Define functions to compute area under the curve.

# Analysis with Error: Graph by drug, using DMSO as a control and model ----------------------------------
library(MESS)
df_subset <- df %>%
  filter(str_detect(treatment, "DMSO")|str_detect(treatment, "Fluphenazine"))

compute_auc <- function(n, p, df_subset){
 # df_subset$id=as.numeric(df_subset$id)
  df_subset <- df_subset %>% filter(str_detect(id, p))
  log_model <- lm(signal~log1p(time), data=df_subset%>%filter(dose==n))
  x <- log_model$model$signal
  y <- log_model$model$`log1p(time)`
  z <- auc(x,y)
  return(z)
}

compute_auc_sets <- function(name, df){
  df_subset <- df %>%
    filter(str_detect(treatment, "DMSO")|str_detect(treatment, name))
  
  c <- (df_subset %>% ungroup() %>% distinct(dose, id))$dose
  d <- (df_subset %>% ungroup() %>% distinct(dose, id))$id
  
  new <- tibble(
    dose=c
  )
  
  new <- df_subset %>% ungroup() %>% distinct(dose, id)
  
  new_auc <- new %>%
    rowwise() %>%
    mutate(auc=compute_auc(dose, id, df_subset)) %>%
    arrange(dose) %>%
    group_by(dose) %>%
    mutate(avg=mean(auc)) %>%
    ungroup() %>%
    mutate(percInhibition=auc/first(avg))
  
  return(as_tibble(new_auc))
}

Run the AUC analysis. Note that wells with decreased cell viability are filtered out here!

# Extract out drug treatment names
x <- (df %>% ungroup() %>% distinct(treatment) %>%
        filter(!(str_detect(treatment, "nothing")|str_detect(treatment, "DMSO"))))$treatment

# Re Do on a subset
# Run AUC analysis on each treatment and bind data frames together
df_run <- df %>% filter(percLive>70) #Filter out data where cell viability is below 70%
analysis <- x %>%
  map(~ compute_auc_sets(.x, df_run) %>% mutate(treatment=.x)) %>%
  map_dfr(~ as.data.frame(.))

Graph the AUC analysis

Use calcein AM staining as a way of normalizing cell numbers (use df_norm tibble). Run normalization prior to computing AUC by dividing the red signal by the percent viability.

Re run analysis as above using calcein AM normalization, but now with the strictest gating (df_norm_subset)

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgcGhhZ29jeXRvc2lzIHZhbGlkYXRpb24gZGF0YSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkodmlyaWRpcykKCnNldHdkKCJ+L0JveC9TaGFyZWFibGUgRmlsZXMvU3RhbmZvcmQvQ2xhc3Nlcy9TUEFSSy9TY3JlZW4gQW5hbHlzaXMiKQpgYGAKCkltcG9ydCBkYXRhc2V0cwpgYGB7ciwgcmVzdWx0cz0naGlkZScsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQpwbGF0ZTFfcmVkX3JhdyA8LSByZWFkX3RzdigiZGF0YS9wbGF0ZSAxIHRvdGFsIGludGVncmF0ZWQgaW50ZW5zaXR5LnR4dCIsIHNraXA9NikKcGxhdGUyX3JlZF9yYXcgPC0gcmVhZF90c3YoImRhdGEvcGxhdGUgMiB0b3RhbCBpbnRlZ3JhdGVkIGludGVuc2l0eS50eHQiLCBza2lwPTYpCgpwbGF0ZTFfZ3JlZW5fcmF3IDwtIHJlYWRfdHN2KCJkYXRhL2xpdmUgb2JqZWN0IGFyZWEgdW0yIHZlciAxLnR4dCIsIHNraXA9NikKcGxhdGUyX2dyZWVuX3JhdyA8LSByZWFkX3RzdigiZGF0YS9saXZlIG9iamVjdCBhcmVhIHVtMiB2ZXIgMi50eHQiLCBza2lwPTYpCgphbm5vdGF0aW9ucyA8LSByZWFkX3hsc3goImRhdGEvYW5ub3RhdGlvbnMueGxzeCIpCmBgYAoKRGVmaW5lIGEgbmV3IHRoZW1lIGZvciBncmFwaHMKCmBgYHtyfQp0aGVtZV9teSA8LSBmdW5jdGlvbihiYXNlX3NpemUgPSAxMCwgYmFzZV9mYW1pbHkgPSAiSGVsdmV0aWNhIikKewogIHR4dCA8LSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiYmxhY2siLCBmYWNlID0gInBsYWluIikKICBib2xkX3R4dCA8LSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvdXIgPSAiYmxhY2siLCBmYWNlID0gImJvbGQiKQogIAogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IGJhc2Vfc2l6ZSwgYmFzZV9mYW1pbHkgPSBiYXNlX2ZhbWlseSkgKwogICAgdGhlbWUoCiAgICAgIAogICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgIAogICAgICB0ZXh0ID0gdHh0LCAKICAgICAgcGxvdC50aXRsZSA9IHR4dCwgCiAgICAgIAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksIAogICAgICAKICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZT0iYm9sZCIpLCAKICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAKICAgICAgYXhpcy50aWNrcy5sZW5ndGg9dW5pdCg0LCAicHQiKSwKICAgICAgCiAgICAgICNheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChtYXJnaW49dW5pdChjKDQsNCw0LDQpLCAicHQiKSksCiAgICAgICNheGlzLnRleHQueC50b3AgPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAjYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQobWFyZ2luPXVuaXQoYyg0LDQsNCw0KSwgInB0IikpLAogICAgICAjYXhpcy50ZXh0LnkucmlnaHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgIHBhbmVsLmdyaWQ9ZWxlbWVudF9ibGFuaygpLAogICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYyhiYXNlX3NpemUsIGJhc2Vfc2l6ZSwgYmFzZV9zaXplLCBiYXNlX3NpemUpLCAicHQiKQogICAgKSAKfQpgYGAKCgpNYXRjaCBhbm5vdGF0aW9ucyB0byBlYWNoIGNvbHVtbgpgYGB7cn0KYW5ub3RhdGlvbnNfcGFyc2VkIDwtIGFubm90YXRpb25zICU+JQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gImNlbGwiLCB2YWx1ZXNfdG89InRyZWF0bWVudCIpICU+JQogIHNlcGFyYXRlKHRyZWF0bWVudCwgaW50bz1jKCJ0cmVhdG1lbnQiLCAiZG9zZSIpLCBzZXA9Il8iKQoKYGBgCgoKQ3JlYXRlIGEgZnVuY3Rpb24gdG8gbWVyZ2UgZGF0YXNldCBhbmQgYW5ub3RhdGUKYGBge3J9Cm1lcmdlIDwtIGZ1bmN0aW9uKHBsYXRlMV9yYXcsIHBsYXRlMl9yYXcsIG5vdGVzKXsKICAKICBwbGF0ZTEgPC0gcGxhdGUxX3JhdyAlPiUKICAgIHNlbGVjdCgtYERhdGUgVGltZWApICU+JQogICAgcGl2b3RfbG9uZ2VyKC1FbGFwc2VkLCBuYW1lc190bz0iY2VsbCIsIHZhbHVlc190bz0ic2lnbmFsIikgJT4lCiAgICBtdXRhdGUoaWQ9cGFzdGUwKGNlbGwsIl8xIikpCiAgCiAgcGxhdGUyIDwtIHBsYXRlMl9yYXcgJT4lCiAgICBzZWxlY3QoLWBEYXRlIFRpbWVgKSAlPiUKICAgIHBpdm90X2xvbmdlcigtRWxhcHNlZCwgbmFtZXNfdG89ImNlbGwiLCB2YWx1ZXNfdG89InNpZ25hbCIpICU+JQogICAgbXV0YXRlKGlkPXBhc3RlMChjZWxsLCJfMiIpKQoKICBkZl9uZXcgPC0gcGxhdGUxICU+JQogICAgZnVsbF9qb2luKHBsYXRlMikgJT4lCiAgICBsZWZ0X2pvaW4obm90ZXMsIGJ5PSJjZWxsIikgJT4lCiAgICBtdXRhdGUoZG9zZT1hcy5udW1lcmljKGRvc2UpKQogIAogIHJldHVybihkZl9uZXcpCn0KCmBgYAoKClBhcnNlIHRoZSBkYXRhIGZvciBwbGF0ZXMgMSBhbmQgMiBhbmQgbWVyZ2UgYW5ub3RhdGlvbnMgaW4uClBlcmZvcm0gdGhpcyBmb3IgZ3JlZW4gcGxhdGVzICh2aWFiaWxpdHkpIGFuZCByZWQgKHBoYWdvY3l0b3NpcykuClRoZW4gY3JlYXRlIGEgc2luZ2xlIG1hc3RlciBkYXRhc2V0IHdpdGggcGhhZ29jeXRvc2lzIGFuZCB2aWFiaWxpdHkuCmBgYHtyLCBtZXNzYWdlPUZ9CmRmX2xpdmUgPC0gbWVyZ2UocGxhdGUxX2dyZWVuX3JhdywgcGxhdGUyX2dyZWVuX3JhdywgYW5ub3RhdGlvbnNfcGFyc2VkKQpkZl9yZWQgPC0gbWVyZ2UocGxhdGUxX3JlZF9yYXcsIHBsYXRlMl9yZWRfcmF3LCBhbm5vdGF0aW9uc19wYXJzZWQpCgpgYGAKCgpHcmFwaCB0aGUgdmlhYmlsaXR5IGRhdGEKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yfQpkZl9saXZlX2dyYXBoIDwtIGRmX2xpdmUgJT4lCiAgZ3JvdXBfYnkoZG9zZSwgdHJlYXRtZW50KSAlPiUKICBtdXRhdGUoc2lnbmFsX2F2ZXJhZ2U9bWVhbihzaWduYWwpLAogICAgICAgICAgICByYW5nZT1tYXgoc2lnbmFsKS1taW4oc2lnbmFsKSwKICAgICAgICAgICAgc2Q9c2Qoc2lnbmFsKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShtYXhMaXZlPWZpcnN0KHNpZ25hbF9hdmVyYWdlKSwKICAgICAgICAgc2RMaXZlPXNkL3NpZ25hbF9hdmVyYWdlKm1heExpdmUpICU+JQogIG11dGF0ZShwZXJjTGl2ZT1zaWduYWxfYXZlcmFnZS9tYXhMaXZlKjEwMCkKCmRmX2xpdmVfZ3JhcGggJT4lCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHRyZWF0bWVudCwgIkRNU08iKSYhc3RyX2RldGVjdCh0cmVhdG1lbnQsICJub3RoaW5nIikpICU+JQogIGRpc3RpbmN0KHRyZWF0bWVudCwgZG9zZSwgcGVyY0xpdmUpICU+JQogIGdncGxvdChhZXMoZG9zZSwgcGVyY0xpdmUsIGNvbG9yPWRvc2UpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgY29sPSJibGFjayIpICsgCiAgZ2VvbV9wb2ludCgpICsKICAjZ2VvbV9lcnJvcmJhcihhZXMoeW1heD1zaWduYWxfYXZlcmFnZStyYW5nZS8yLCB5bWluPXNpZ25hbF9hdmVyYWdlLXJhbmdlLzIpLCB3aWR0aD0wKSArCiAgI2dlb21fZXJyb3JiYXIoYWVzKHltYXg9cGVyY0xpdmUrc2RMaXZlLCB5bWluPXBlcmNMaXZlLXNkTGl2ZSksIHdpZHRoPTApICsKICAjZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIGZvcm11bGEgPSB5IH4gc3BsaW5lczo6YnMoeCwgMSksIGNvbG9yPSJyZWQiKSArCiAgI2dlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBmb3JtdWxhID0geSB+IGxvZzFwKHgpLCBjb2xvcj0icmVkIiwgc2U9RikgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlyZWN0aW9uPS0xLCBvcHRpb249Im1hZ21hIiwgYmVnaW49MCwgZW5kPS44KSArCiAgZ2VvbV9wb2ludChkYXRhPWRmX2xpdmVfZ3JhcGglPiVmaWx0ZXIocGVyY0xpdmU8NzApLCBjb2xvcj0icmVkIiwgc2l6ZT0zLCBzaGFwZT0yMSkgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgI2xhYnMoeD0iRG9zZSAobk0pIiwgeT0iUGVyY2VudCBWYWliaWxpdHkiKSArCiAgbGFicyh4PSJEb3NlIChuTSkiLCB5PSJDYWxjZWluIEFNICglKSIpICsKICBmYWNldF9ncmlkKC5+dHJlYXRtZW50KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNzAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yPSJyZWQiKSArCiAgdGhlbWVfbXkoKQoKZ2dzYXZlKCJ2aWFiaWxpdHktNzBwZXJjLXRocmVzaG9sZC1uZXcucGRmIiwgaGVpZ2h0PTEuNzUsIHdpZHRoPTEyKQpgYGAKCgpQaGFnb2N5dG9zaXMgZGF0YS4KU3RhcnQgYnkgYWRkaW5nIGluIHRoZSB2aWFiaWxpdHkgZGF0YQpgYGB7cn0KZGYgPC0gZGZfcmVkICU+JQogIGZ1bGxfam9pbihkZl9saXZlX2dyYXBoLCBieT0iaWQiKSAlPiUKICBzZWxlY3QoLWMoIkVsYXBzZWQueSIsICJjZWxsLnkiLCAidHJlYXRtZW50LnkiLCAiZG9zZS55IikpICU+JQogIHJlbmFtZSh0aW1lPUVsYXBzZWQueCwgY2VsbD1jZWxsLngsIHNpZ25hbD1zaWduYWwueCwgdHJlYXRtZW50PXRyZWF0bWVudC54LCBkb3NlPWRvc2UueCwgc2lnbmFsLmdyZWVuPXNpZ25hbC55LAogICAgICAgICByYW5nZS5ncmVlbj1yYW5nZSwgcmFuZ2Uuc2Q9c2QpCgpgYGAKCkdyYXBoIGFsbCBwaGFnb2N5dG9zaXMgZGF0YS4KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KZGYgJT4lCiAgZ3JvdXBfYnkodHJlYXRtZW50LCBkb3NlLCB0aW1lKSAlPiUKICBtdXRhdGUoc2lnbmFsX2F2ZXJhZ2U9bWVhbihzaWduYWwpLAogICAgICAgICByYW5nZT1tYXgoc2lnbmFsKS1taW4oc2lnbmFsKSwKICAgICAgICAgc2Q9c2Qoc2lnbmFsKSkgJT4lCiAgZ2dwbG90KGFlcyh0aW1lLCBzaWduYWxfYXZlcmFnZSwgZ3JvdXA9ZG9zZSwgY29sb3I9ZG9zZSkpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBmb3JtdWxhID0geSB+IGxvZzFwKHgpLCBjb2xvcj0iYmxhY2siLCBzZT1GKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgI2dlb21fZXJyb3JiYXIoYWVzKHltYXg9c2lnbmFsX2F2ZXJhZ2UrcmFuZ2UvMiwgeW1pbj1zaWduYWxfYXZlcmFnZS1yYW5nZS8yKSwgd2lkdGg9MCkgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1heD1zaWduYWxfYXZlcmFnZStzZCwgeW1pbj1zaWduYWxfYXZlcmFnZS1zZCksIHdpZHRoPTApICsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlyZWN0aW9uPS0xLCBvcHRpb249Im1hZ21hIiwgYmVnaW49MCwgZW5kPS44KSArCiAgICBmYWNldF9ncmlkKHRyZWF0bWVudH5kb3NlKSsKICAgIHRoZW1lX215KCkKYGBgCgpUcnkgbm9ybWFsaXppbmcgdGhlIHBoYWdvY3l0b3NpcyBzaWduYWwgdG8gcGVyY2VudCB2aWFiaWxpdHkuCmBgYHtyfQpkZl9ub3JtIDwtIGRmICU+JQogIG11dGF0ZShzaWduYWw9c2lnbmFsL3BlcmNMaXZlLzEwMCkKYGBgCgoKR3JhcGggdGhlIG5vcm1hbGl6ZWQgcGhhZ29jeXRvc2lzIGRhdGEgYWdhaW4uCkFsc28gZ2F0ZSBvbmx5IG9uIGNvbmRpdGlvbnMgd2hlcmU6CiAgLSB2aWFiaWxpdHkgaXMgYWJvdmUgNzAlCiAgLSBzZCBpcyBub3QgaHVnZSAoc2QgbXVzdCBiZSBoYWxmIHRoZSBtZWFuIG9mIGEgZ2l2ZW4gdmFsdWUpCiAgLSBtb3N0IG9mIHRoZSBkYXRhIHBvaW50cyBhcmUgc3RpbGwgcHJlc2VudCBmb3IgYSBnaXZlbiBjb25kaXRpb24KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KZGZfbm9ybV9zdWJzZXQgPC0gZGZfbm9ybSAlPiUKICBmaWx0ZXIocGVyY0xpdmU+NzApICU+JSAjIEdhdGUgb25seSBvbiB3ZWxscyB3aGVyZSB2aWFiaWxpdHkgZGV0ZXJtaW5lZCB0byBiZSBncmVhdGVyIHRoYW4gNzAmCiAgZ3JvdXBfYnkodHJlYXRtZW50LCBkb3NlLCB0aW1lKSAlPiUKICBtdXRhdGUoc2lnbmFsX2F2ZXJhZ2U9bWVhbihzaWduYWwpLAogICAgICAgICByYW5nZT1tYXgoc2lnbmFsKS1taW4oc2lnbmFsKSwKICAgICAgICAgc2Q9c2Qoc2lnbmFsKSkgJT4lCiAgZmlsdGVyKHNkPHNpZ25hbF9hdmVyYWdlLzIpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieSh0cmVhdG1lbnQsIGRvc2UpICU+JQogIGZpbHRlcihuKCk+NDgpICNIZXJlIGdhdGluZyBvbiB0cmVhdG1lbnRzIC8gZG9zZXMgd2hlcmUgbW9zdCBvZiB0aGUgZGF0YSBwb2l0bnMgYXJlIHN0aWxsIHByZXNlbnQKCmRmX25vcm1fc3Vic2V0ICU+JQogIGdncGxvdChhZXModGltZSwgc2lnbmFsX2F2ZXJhZ2UsIGdyb3VwPWRvc2UsIGNvbG9yPWRvc2UpKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgZm9ybXVsYSA9IHkgfiBsb2cxcCh4KSwgY29sb3I9ImJsYWNrIiwgc2U9RikgKwogICAgZ2VvbV9wb2ludCgpICsKICAgICNnZW9tX2Vycm9yYmFyKGFlcyh5bWF4PXNpZ25hbF9hdmVyYWdlK3JhbmdlLzIsIHltaW49c2lnbmFsX2F2ZXJhZ2UtcmFuZ2UvMiksIHdpZHRoPTApICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltYXg9c2lnbmFsX2F2ZXJhZ2Urc2QsIHltaW49c2lnbmFsX2F2ZXJhZ2Utc2QpLCB3aWR0aD0wKSArCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzKGRpcmVjdGlvbj0tMSwgb3B0aW9uPSJtYWdtYSIsIGJlZ2luPTAsIGVuZD0uOCkgKwogICAgZmFjZXRfZ3JpZCh0cmVhdG1lbnR+ZG9zZSkrCiAgICB0aGVtZV9teSgpCmBgYAoKCkdyYXBoIFNhbG1ldGVyb2wgcGhhZ29jeXRvc2lzIGRhdGEgb25seS4KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xLjV9CmRmICU+JQogIGdyb3VwX2J5KHRyZWF0bWVudCwgZG9zZSwgdGltZSkgJT4lCiAgbXV0YXRlKHNpZ25hbF9hdmVyYWdlPW1lYW4oc2lnbmFsKSwKICAgICAgICAgcmFuZ2U9bWF4KHNpZ25hbCktbWluKHNpZ25hbCksCiAgICAgICAgIHNkPXNkKHNpZ25hbCksCiAgICAgICAgIHNlPXNkKHNpZ25hbCkvc3FydChuKCkpKSAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdCh0cmVhdG1lbnQsICJETVNPIil8c3RyX2RldGVjdCh0cmVhdG1lbnQsICJTYWxtZXRlcm9sIikpICU+JQogIGdncGxvdChhZXModGltZSwgc2lnbmFsX2F2ZXJhZ2UsIGdyb3VwPWRvc2UsIGNvbG9yPWRvc2UpKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgZm9ybXVsYSA9IHkgfiBsb2cxcCh4KSwgY29sb3I9ImJsYWNrIiwgc2U9RikgKwogICAgZ2VvbV9wb2ludCgpICsKICAgICNnZW9tX2Vycm9yYmFyKGFlcyh5bWF4PXNpZ25hbF9hdmVyYWdlK3JhbmdlLzIsIHltaW49c2lnbmFsX2F2ZXJhZ2UtcmFuZ2UvMiksIHdpZHRoPTApICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltYXg9c2lnbmFsX2F2ZXJhZ2Urc2UsIHltaW49c2lnbmFsX2F2ZXJhZ2Utc2UpLCB3aWR0aD0wKSArCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzKGRpcmVjdGlvbj0tMSwgb3B0aW9uPSJtYWdtYSIsIGJlZ2luPTAsIGVuZD0uOCkgKwogICAgZmFjZXRfZ3JpZCgufmRvc2UpKwogICAgdGhlbWVfbXkoKQoKZ2dzYXZlKCJyYXctc2FsbWV0ZXJvbC1vbmx5LnBkZiIsIHVzZURpbmdiYXRzPUYsIGhlaWdodD0yLCB3aWR0aD0xMikKYGBgCgpHcmFwaCBNb3hvbmlkaW5lIHBoYWdvY3l0b3NpcyBkYXRhIG9ubHkuCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MS41fQpkZiAlPiUKICBncm91cF9ieSh0cmVhdG1lbnQsIGRvc2UsIHRpbWUpICU+JQogIG11dGF0ZShzaWduYWxfYXZlcmFnZT1tZWFuKHNpZ25hbCksCiAgICAgICAgIHJhbmdlPW1heChzaWduYWwpLW1pbihzaWduYWwpLAogICAgICAgICBzZD1zZChzaWduYWwpLAogICAgICAgICBzZT1zZChzaWduYWwpL3NxcnQobigpKSkgJT4lCiAgZmlsdGVyKHN0cl9kZXRlY3QodHJlYXRtZW50LCAiRE1TTyIpfHN0cl9kZXRlY3QodHJlYXRtZW50LCAiTW94b25pZGluZSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHRpbWUsIHNpZ25hbF9hdmVyYWdlLCBncm91cD1kb3NlLCBjb2xvcj1kb3NlKSkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIGZvcm11bGEgPSB5IH4gbG9nMXAoeCksIGNvbG9yPSJibGFjayIsIHNlPUYpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICAjZ2VvbV9lcnJvcmJhcihhZXMoeW1heD1zaWduYWxfYXZlcmFnZStyYW5nZS8yLCB5bWluPXNpZ25hbF9hdmVyYWdlLXJhbmdlLzIpLCB3aWR0aD0wKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWF4PXNpZ25hbF9hdmVyYWdlK3NlLCB5bWluPXNpZ25hbF9hdmVyYWdlLXNlKSwgd2lkdGg9MCkgKwogICAgc2NhbGVfY29sb3JfdmlyaWRpcyhkaXJlY3Rpb249LTEsIG9wdGlvbj0ibWFnbWEiLCBiZWdpbj0wLCBlbmQ9LjgpICsKICAgIGZhY2V0X2dyaWQoLn5kb3NlKSsKICAgIHRoZW1lX215KCkKYGBgCgoKUGVyZm9ybSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZSBhbmFseXNpcy4KRGVmaW5lIGZ1bmN0aW9ucyB0byBjb21wdXRlIGFyZWEgdW5kZXIgdGhlIGN1cnZlLgpgYGB7cn0KIyBBbmFseXNpcyB3aXRoIEVycm9yOiBHcmFwaCBieSBkcnVnLCB1c2luZyBETVNPIGFzIGEgY29udHJvbCBhbmQgbW9kZWwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpsaWJyYXJ5KE1FU1MpCmRmX3N1YnNldCA8LSBkZiAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdCh0cmVhdG1lbnQsICJETVNPIil8c3RyX2RldGVjdCh0cmVhdG1lbnQsICJGbHVwaGVuYXppbmUiKSkKCmNvbXB1dGVfYXVjIDwtIGZ1bmN0aW9uKG4sIHAsIGRmX3N1YnNldCl7CiAjIGRmX3N1YnNldCRpZD1hcy5udW1lcmljKGRmX3N1YnNldCRpZCkKICBkZl9zdWJzZXQgPC0gZGZfc3Vic2V0ICU+JSBmaWx0ZXIoc3RyX2RldGVjdChpZCwgcCkpCiAgbG9nX21vZGVsIDwtIGxtKHNpZ25hbH5sb2cxcCh0aW1lKSwgZGF0YT1kZl9zdWJzZXQlPiVmaWx0ZXIoZG9zZT09bikpCiAgeCA8LSBsb2dfbW9kZWwkbW9kZWwkc2lnbmFsCiAgeSA8LSBsb2dfbW9kZWwkbW9kZWwkYGxvZzFwKHRpbWUpYAogIHogPC0gYXVjKHgseSkKICByZXR1cm4oeikKfQoKY29tcHV0ZV9hdWNfc2V0cyA8LSBmdW5jdGlvbihuYW1lLCBkZil7CiAgZGZfc3Vic2V0IDwtIGRmICU+JQogICAgZmlsdGVyKHN0cl9kZXRlY3QodHJlYXRtZW50LCAiRE1TTyIpfHN0cl9kZXRlY3QodHJlYXRtZW50LCBuYW1lKSkKICAKICBjIDwtIChkZl9zdWJzZXQgJT4lIHVuZ3JvdXAoKSAlPiUgZGlzdGluY3QoZG9zZSwgaWQpKSRkb3NlCiAgZCA8LSAoZGZfc3Vic2V0ICU+JSB1bmdyb3VwKCkgJT4lIGRpc3RpbmN0KGRvc2UsIGlkKSkkaWQKICAKICBuZXcgPC0gdGliYmxlKAogICAgZG9zZT1jCiAgKQogIAogIG5ldyA8LSBkZl9zdWJzZXQgJT4lIHVuZ3JvdXAoKSAlPiUgZGlzdGluY3QoZG9zZSwgaWQpCiAgCiAgbmV3X2F1YyA8LSBuZXcgJT4lCiAgICByb3d3aXNlKCkgJT4lCiAgICBtdXRhdGUoYXVjPWNvbXB1dGVfYXVjKGRvc2UsIGlkLCBkZl9zdWJzZXQpKSAlPiUKICAgIGFycmFuZ2UoZG9zZSkgJT4lCiAgICBncm91cF9ieShkb3NlKSAlPiUKICAgIG11dGF0ZShhdmc9bWVhbihhdWMpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShwZXJjSW5oaWJpdGlvbj1hdWMvZmlyc3QoYXZnKSkKICAKICByZXR1cm4oYXNfdGliYmxlKG5ld19hdWMpKQp9CmBgYAoKUnVuIHRoZSBBVUMgYW5hbHlzaXMuIE5vdGUgdGhhdCB3ZWxscyB3aXRoIGRlY3JlYXNlZCBjZWxsIHZpYWJpbGl0eSBhcmUgZmlsdGVyZWQgb3V0IGhlcmUhCmBgYHtyfQojIEV4dHJhY3Qgb3V0IGRydWcgdHJlYXRtZW50IG5hbWVzCnggPC0gKGRmICU+JSB1bmdyb3VwKCkgJT4lIGRpc3RpbmN0KHRyZWF0bWVudCkgJT4lCiAgICAgICAgZmlsdGVyKCEoc3RyX2RldGVjdCh0cmVhdG1lbnQsICJub3RoaW5nIil8c3RyX2RldGVjdCh0cmVhdG1lbnQsICJETVNPIikpKSkkdHJlYXRtZW50CgojIFJlIERvIG9uIGEgc3Vic2V0CiMgUnVuIEFVQyBhbmFseXNpcyBvbiBlYWNoIHRyZWF0bWVudCBhbmQgYmluZCBkYXRhIGZyYW1lcyB0b2dldGhlcgpkZl9ydW4gPC0gZGYgJT4lIGZpbHRlcihwZXJjTGl2ZT43MCkgI0ZpbHRlciBvdXQgZGF0YSB3aGVyZSBjZWxsIHZpYWJpbGl0eSBpcyBiZWxvdyA3MCUKYW5hbHlzaXMgPC0geCAlPiUKICBtYXAofiBjb21wdXRlX2F1Y19zZXRzKC54LCBkZl9ydW4pICU+JSBtdXRhdGUodHJlYXRtZW50PS54KSkgJT4lCiAgbWFwX2Rmcih+IGFzLmRhdGEuZnJhbWUoLikpCgpgYGAKCkdyYXBoIHRoZSBBVUMgYW5hbHlzaXMKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yfQojIEdyYXBoIG5ldyBhbmFseXNpcwphbmFseXNpc19ncmFwaCA8LSBhc190aWJibGUoYW5hbHlzaXMpICU+JSBsZWZ0X2pvaW4oZGZfcnVuLCBieT1jKCJ0cmVhdG1lbnQiLCAiZG9zZSIpKSAlPiUKIyAgZmlsdGVyKHN0cl9kZXRlY3QodHJlYXRtZW50LCAiU2FsbWV0ZXJvbCIpfHN0cl9kZXRlY3QodHJlYXRtZW50LCAiTW94b25pZGluZSIpKSAlPiUgIyBBZGQgdGhpcyBsaW5lIGlmIGZpbHRlcmluZyBvbiBjZXJ0YWluIGRydWdzIGRlc2lyZWQuCiAgZ3JvdXBfYnkodHJlYXRtZW50LCBkb3NlKSAlPiUKICBtdXRhdGUobWVhbj1tZWFuKHBlcmNJbmhpYml0aW9uKSwKICAgICAgICAgc2Q9c2QocGVyY0luaGliaXRpb24pLAogICAgICAgICBzZT1zZC9zcXJ0KG4oKSkpCmFuYWx5c2lzX2dyYXBoICU+JQogIGdncGxvdChhZXMoZG9zZSwgbWVhbikpICsKICBnZW9tX2xpbmUoYWxwaGE9MC4zKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3BvaW50KGRhdGE9YW5hbHlzaXNfZ3JhcGggJT4lIGZpbHRlcihwZXJjTGl2ZTw3MCksIGNvbG9yPSJyZWQiLCBzaGFwZT0yMSwgc2l6ZT0zKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLCB5bWF4PW1lYW4rc2UpLCBhbHBoYT0wLjMpICsKICBmYWNldF9ncmlkKC5+dHJlYXRtZW50KSArCiAgI2dlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBzZT1GKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKC4xNSwyLjEpKSArCiAgbGFicyh4PSJDb25jZW50cmF0aW9uIChuTSkiLCB5PSJJbmhpYml0aW9uIChBVUMgRnJhY3Rpb24pIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yPSJyZWQiKSArCiAgdGhlbWVfbXkoKQoKZ2dzYXZlKCJhcmVhLXVuZGVyLWN1cnZlLTcwcGVyYy12aWFiaWxpdHktdGhyZXNob2xkLWFsbC1lcnJvci5wZGYiLCB1c2VEaW5nYmF0cz1GLCBoZWlnaHQ9Miwgd2lkdGg9MTIpCmdnc2F2ZSgiYXJlYS11bmRlci1jdXJ2ZS03MHBlcmMtdmlhYmlsaXR5LXRocmVzaG9sZC1zZWxlY3RlZC1lcnJvci5wZGYiLCB1c2VEaW5nYmF0cz1GLCBoZWlnaHQ9Miwgd2lkdGg9MykgIyB3aGVuIG9ubHkgdHdvIHRyZWF0bWVudHMgc2VsZWN0ZWQgdG8gZ3JhcGgKCmBgYAoKVXNlIGNhbGNlaW4gQU0gc3RhaW5pbmcgYXMgYSB3YXkgb2Ygbm9ybWFsaXppbmcgY2VsbCBudW1iZXJzICh1c2UgZGZfbm9ybSB0aWJibGUpLgpSdW4gbm9ybWFsaXphdGlvbiBwcmlvciB0byBjb21wdXRpbmcgQVVDIGJ5IGRpdmlkaW5nIHRoZSByZWQgc2lnbmFsIGJ5IHRoZSBwZXJjZW50IHZpYWJpbGl0eS4KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yfQp4IDwtIChkZl9ub3JtICU+JSB1bmdyb3VwKCkgJT4lIGRpc3RpbmN0KHRyZWF0bWVudCkgJT4lCiAgICAgICAgZmlsdGVyKCEoc3RyX2RldGVjdCh0cmVhdG1lbnQsICJub3RoaW5nIil8c3RyX2RldGVjdCh0cmVhdG1lbnQsICJETVNPIikpKSkkdHJlYXRtZW50CgojIFJlIERvIG9uIGEgc3Vic2V0CiMgUnVuIEFVQyBhbmFseXNpcyBvbiBlYWNoIHRyZWF0bWVudCBhbmQgYmluZCBkYXRhIGZyYW1lcyB0b2dldGhlcgpkZl9ydW4gPC0gZGZfbm9ybSAlPiUgZmlsdGVyKHBlcmNMaXZlPjcwKSAjRmlsdGVyIG91dCBkYXRhIHdoZXJlIGNlbGwgdmlhYmlsaXR5IGlzIGJlbG93IDcwJQphbmFseXNpcyA8LSB4ICU+JQogIG1hcCh+IGNvbXB1dGVfYXVjX3NldHMoLngsIGRmX3J1bikgJT4lIG11dGF0ZSh0cmVhdG1lbnQ9LngpKSAlPiUKICBtYXBfZGZyKH4gYXMuZGF0YS5mcmFtZSguKSkKCgphbmFseXNpc19ncmFwaCA8LSBhc190aWJibGUoYW5hbHlzaXMpICU+JSBsZWZ0X2pvaW4oZGZfcnVuLCBieT1jKCJ0cmVhdG1lbnQiLCAiZG9zZSIpKSAlPiUKIyAgIGZpbHRlcihzdHJfZGV0ZWN0KHRyZWF0bWVudCwgIlNhbG1ldGVyb2wiKXxzdHJfZGV0ZWN0KHRyZWF0bWVudCwgIk1veG9uaWRpbmUiKSkgJT4lICMgQWRkIHRoaXMgbGluZSBpZiBmaWx0ZXJpbmcgb24gY2VydGFpbiBkcnVncyBkZXNpcmVkLgogIGdyb3VwX2J5KHRyZWF0bWVudCwgZG9zZSkgJT4lCiAgbXV0YXRlKG1lYW49bWVhbihwZXJjSW5oaWJpdGlvbiksCiAgICAgICAgIHNkPXNkKHBlcmNJbmhpYml0aW9uKSwKICAgICAgICAgc2U9c2Qvc3FydChuKCkpKQphbmFseXNpc19ncmFwaCAlPiUKICBnZ3Bsb3QoYWVzKGRvc2UsIG1lYW4pKSArCiAgZ2VvbV9saW5lKGFscGhhPTAuMykgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9wb2ludChkYXRhPWFuYWx5c2lzX2dyYXBoICU+JSBmaWx0ZXIocGVyY0xpdmU8NzApLCBjb2xvcj0icmVkIiwgc2hhcGU9MjEsIHNpemU9MykgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1zZSwgeW1heD1tZWFuK3NlKSwgYWxwaGE9MC4zKSArCiAgZmFjZXRfZ3JpZCgufnRyZWF0bWVudCkgKwogICNnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgc2U9RikgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHM9YyguMTUsMi4xKSkgKwogIGxhYnMoeD0iQ29uY2VudHJhdGlvbiAobk0pIiwgeT0iSW5oaWJpdGlvbiAoQVVDIEZyYWN0aW9uKSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvcj0icmVkIikgKwogIHRoZW1lX215KCkKCmdnc2F2ZSgiYXJlYS11bmRlci1jdXJ2ZS03MHBlcmMtdmlhYmlsaXR5LXRocmVzaG9sZC1hbGwtZXJyb3Itbm9ybWFsaXplZC5wZGYiLCB1c2VEaW5nYmF0cz1GLCBoZWlnaHQ9Miwgd2lkdGg9MTIpCmdnc2F2ZSgiYXJlYS11bmRlci1jdXJ2ZS03MHBlcmMtdmlhYmlsaXR5LXRocmVzaG9sZC1zZWxlY3RlZC1lcnJvci1ub3JtYWxpemVkLnBkZiIsIHVzZURpbmdiYXRzPUYsIGhlaWdodD0yLCB3aWR0aD0zKSAjIHdoZW4gb25seSB0d28gdHJlYXRtZW50cyBzZWxlY3RlZCB0byBncmFwaAoKYGBgCgoKUmUgcnVuIGFuYWx5c2lzIGFzIGFib3ZlIHVzaW5nIGNhbGNlaW4gQU0gbm9ybWFsaXphdGlvbiwgYnV0IG5vdyB3aXRoIHRoZSBzdHJpY3Rlc3QgZ2F0aW5nIChkZl9ub3JtX3N1YnNldCkKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0yfQp4IDwtIChkZl9ub3JtX3N1YnNldCAlPiUgdW5ncm91cCgpICU+JSBkaXN0aW5jdCh0cmVhdG1lbnQpICU+JQogICAgICAgIGZpbHRlcighKHN0cl9kZXRlY3QodHJlYXRtZW50LCAibm90aGluZyIpfHN0cl9kZXRlY3QodHJlYXRtZW50LCAiRE1TTyIpKSkpJHRyZWF0bWVudAoKIyBSZSBEbyBvbiBhIHN1YnNldAojIFJ1biBBVUMgYW5hbHlzaXMgb24gZWFjaCB0cmVhdG1lbnQgYW5kIGJpbmQgZGF0YSBmcmFtZXMgdG9nZXRoZXIKZGZfcnVuIDwtIGRmX25vcm1fc3Vic2V0ICU+JSBmaWx0ZXIocGVyY0xpdmU+NzApICNGaWx0ZXIgb3V0IGRhdGEgd2hlcmUgY2VsbCB2aWFiaWxpdHkgaXMgYmVsb3cgNzAlCmFuYWx5c2lzIDwtIHggJT4lCiAgbWFwKH4gY29tcHV0ZV9hdWNfc2V0cygueCwgZGZfcnVuKSAlPiUgbXV0YXRlKHRyZWF0bWVudD0ueCkpICU+JQogIG1hcF9kZnIofiBhcy5kYXRhLmZyYW1lKC4pKQoKCmFuYWx5c2lzX2dyYXBoIDwtIGFzX3RpYmJsZShhbmFseXNpcykgJT4lIGxlZnRfam9pbihkZl9ydW4sIGJ5PWMoInRyZWF0bWVudCIsICJkb3NlIikpICU+JQojICAgZmlsdGVyKHN0cl9kZXRlY3QodHJlYXRtZW50LCAiU2FsbWV0ZXJvbCIpfHN0cl9kZXRlY3QodHJlYXRtZW50LCAiTW94b25pZGluZSIpKSAlPiUgIyBBZGQgdGhpcyBsaW5lIGlmIGZpbHRlcmluZyBvbiBjZXJ0YWluIGRydWdzIGRlc2lyZWQuCiAgZ3JvdXBfYnkodHJlYXRtZW50LCBkb3NlKSAlPiUKICBtdXRhdGUobWVhbj1tZWFuKHBlcmNJbmhpYml0aW9uKSwKICAgICAgICAgc2Q9c2QocGVyY0luaGliaXRpb24pLAogICAgICAgICBzZT1zZC9zcXJ0KG4oKSkpCmFuYWx5c2lzX2dyYXBoICU+JQogIGdncGxvdChhZXMoZG9zZSwgbWVhbikpICsKICBnZW9tX2xpbmUoYWxwaGE9MC4zKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3BvaW50KGRhdGE9YW5hbHlzaXNfZ3JhcGggJT4lIGZpbHRlcihwZXJjTGl2ZTw3MCksIGNvbG9yPSJyZWQiLCBzaGFwZT0yMSwgc2l6ZT0zKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNlLCB5bWF4PW1lYW4rc2UpLCBhbHBoYT0wLjMpICsKICBmYWNldF9ncmlkKC5+dHJlYXRtZW50KSArCiAgI2dlb21fc21vb3RoKG1ldGhvZD0ibG9lc3MiLCBzZT1GKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKC4xNSwyLjEpKSArCiAgbGFicyh4PSJDb25jZW50cmF0aW9uIChuTSkiLCB5PSJJbmhpYml0aW9uIChBVUMgRnJhY3Rpb24pIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yPSJyZWQiKSArCiAgdGhlbWVfbXkoKQoKZ2dzYXZlKCJhcmVhLXVuZGVyLWN1cnZlLTcwcGVyYy12aWFiaWxpdHktdGhyZXNob2xkLWFsbC1lcnJvci1ub3JtYWxpemVkLnBkZiIsIHVzZURpbmdiYXRzPUYsIGhlaWdodD0yLCB3aWR0aD0xMikKZ2dzYXZlKCJhcmVhLXVuZGVyLWN1cnZlLTcwcGVyYy12aWFiaWxpdHktdGhyZXNob2xkLXNlbGVjdGVkLWVycm9yLW5vcm1hbGl6ZWQucGRmIiwgdXNlRGluZ2JhdHM9RiwgaGVpZ2h0PTIsIHdpZHRoPTMpICMgd2hlbiBvbmx5IHR3byB0cmVhdG1lbnRzIHNlbGVjdGVkIHRvIGdyYXBoCgpgYGAKCgoKCgoKCgoKCgoKCgo=